﻿using System;

namespace LaoLuo
{
    /// <summary>
    /// 提供类型转换的静态方法
    /// </summary>
    public static class TypeConverter // IConvertible
    {
        /// <summary>
        /// 尝试转换为int,如果发生异常,则返回null
        /// </summary>
        /// <param name="value">要转换的值</param>
        /// <returns>转换的结果</returns>
        public static int? ToNullableInt32(object value)
        {
            return ToNullableType<Int32>(value);
        }

        /// <summary>
        /// 尝试转换为long,如果发生异常,则返回null
        /// </summary>
        /// <param name="value">要转换的值</param>
        /// <returns>转换的结果</returns>
        public static long? ToNullableInt64(object value)
        {
            return ToNullableType<Int64>(value);
        }

        /// <summary>
        /// 尝试转换为DateTime,如果发生异常,则返回null
        /// </summary>
        /// <param name="value">要转换的值</param>
        /// <returns>转换的结果</returns>
        public static DateTime? ToNullableDateTime(object value)
        {
            return ToNullableType<DateTime>(value);
        }

        /// <summary>
        /// 尝试转换为T,如果发生异常,则返回null
        /// </summary>
        /// <param name="value">要转换的值</param>
        /// <returns>转换的结果</returns>
        public static T? ToNullableType<T>(object value)
            where T : struct
        {
            return ToType<T?>(value);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="values"></param>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static T? ToNullableType<T>(params object[] values)
            where T : struct
        {
            foreach (var o in values)
            {
                var ret = ToType<T?>(o);
                if (ret.HasValue)
                {
                    return ret;
                }
            }

            return null;
        }


        /// <summary>
        /// 尝试转换为T,如果发生异常,则返回default(T)
        /// </summary>
        /// <param name="value">要转换的值</param>
        /// <param name="defaultValue">如果转换失败,则返回此指定的默认值</param>
        /// <returns>转换的结果</returns>
        public static T ToType<T>(object value, T defaultValue = default(T))
        {
            try
            {
                var t = typeof(T);

                if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>))
                {
                    t = Nullable.GetUnderlyingType(t);
                }

                if (t.IsEnum)
                {
                    return (T)Enum.Parse(t, value.ToString());
                }

                return (T)Convert.ChangeType(value, t);
            }
            catch
            {
                return defaultValue;
            }
        }

        public static object ToType(object value, Type t)
        {
            var realT = t;

            try
            {
                if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>))
                {
                    t = Nullable.GetUnderlyingType(t);
                }

                if (t.IsEnum)
                {
                    return Enum.Parse(t, value.ToString());
                }

                if (t == typeof(Guid))
                {
                    return new Guid(value.ToString());
                }

                return Convert.ChangeType(value, t);
            }
            catch
            {
                return realT.GetDefault();
            }
        }
    }
}
